﻿using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using KewlStuff.Events;
using MovieBuddy.Controls.MSTB;
using MovieBuddy.Helpers;
using MovieModel.Model;

namespace MovieBuddy.Dialogs
{
    /// <summary>
    /// Interaction logic for NewMovieDialog.xaml
    /// </summary>
    public partial class NewMovieDialog : Window
    {
        private readonly Manager Manager;
        private readonly OneShotHandlerQueue<TextChangedEventArgs> yearChanged = new OneShotHandlerQueue<TextChangedEventArgs>();
        private readonly OneShotHandlerQueue<TextChangedEventArgs> runtimeChanged = new OneShotHandlerQueue<TextChangedEventArgs>();
        private readonly OneShotHandlerQueue<TextChangedEventArgs> nameChanged = new OneShotHandlerQueue<TextChangedEventArgs>();
        private readonly OneShotHandlerQueue<TextChangedEventArgs> movieChanged = new OneShotHandlerQueue<TextChangedEventArgs>();

        private readonly Movie editMovie;
        
        public NewMovieDialog(Manager manager)
        {
            Manager = manager;
            InitializeComponent();
            yearBox.TextChanged += yearChanged.Handle;
            runtimeBox.TextChanged += runtimeChanged.Handle;
            nameBox.TextChanged += nameChanged.Handle;
            movieFilePicker.textBox.TextChanged += movieChanged.Handle;

            tagsBox.ItemsSource = manager.Tags.Values;
            peopleBox.ItemsSource = manager.People.Values;
            companiesBox.ItemsSource = manager.Companies.Values;
            movieFilePicker.SetExtensions("Video Files",
                string.Join(";", MovieConstants.MovieExtensions.Select(e => "*." + e)));
        }

        public NewMovieDialog(Manager manager, Movie movie) : this(manager)
        {
            editMovie = movie;
            Title = "Edit " + movie.Name;
            saveBut.Content = "Save Movie";

            nameBox.Text = movie.Name;
            descriptionBox.Text = movie.Description;
            yearBox.Text = movie.Year == null ? "" : movie.Year.ToString();
            runtimeBox.Text = movie.Runtime == null ? "" : movie.Runtime.ToString();
            movieFilePicker.FileName = movie.MovieFile.FullName;
            imageFilePicker.FileName = movie.ImageLocation;
            tagsBox.Items = movie.Tags.Select(t => new MultiSelectTextBoxItem { Id = t.Id, Text = t.Name });
            companiesBox.Items = movie.Companies.Select(c => new MultiSelectTextBoxItem { Id = c.Id, Text = c.Name });
            peopleBox.Items = movie.People.Select(p => new MultiSelectTextBoxItem { Id = p.Person.Id, Text = p.Person.Name });
        }

        private void ImagePicked(object sender, Controls.FilePickerUpdatedEventArgs e)
        {
            imagePreview.Source = ImageCache.GetImage(e);
        }

        private void CancelButClick(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void SaveButClick(object sender, RoutedEventArgs e)
        {
            try
            {
                int? year = GetTextBoxInteger("year", yearBox, yearChanged);
                int? runtime = GetTextBoxInteger("runtime", runtimeBox, runtimeChanged);
                string name = GetRequiredText("Name", nameBox, nameChanged);
                string image = imageFilePicker.FileName;
                if (movieFilePicker.FileName.Trim().Length == 0)
                {
                    movieChanged.Add((s, a) => errorLabel.Content = "");
                    throw new Exception("Must select a movie file.");
                }
                var movieFile = new FileInfo(movieFilePicker.FileName);
                if (!movieFile.Exists)
                {
                    movieChanged.Add((s, a) => errorLabel.Content = "");
                    throw new Exception("Must select a valid movie file.");
                } 

                if (string.IsNullOrEmpty(image)) image = null;
                string thumb = null;
                if (image != null)
                {
                    if (editMovie != null && editMovie.ImageLocation == image && editMovie.ThumbnailLocation != null)
                    {
                        thumb = editMovie.ThumbnailLocation;
                    }
                    else
                    {
                        var thumbReq = new Manager.ThumbnailRequest(null, 61);
                        image = Manager.ImportFile(new Uri(image), thumbReq).FullName;
                        thumb = thumbReq.File.FullName;
                    }
                }

                var movie = editMovie ?? Movie.CreateNewMovie(name);

                var tags = Manager.GetAndAddTags(tagsBox.Items.Select(i => new Tuple<int?, string>(i.Id, i.Text)));
                var people = Manager.GetAndAddPeople(peopleBox.Items.Select(i => new Tuple<int?, string>(i.Id, i.Text))).Select(p => new MoviePart(p, Role.Actor, movie));
                var companies = Manager.GetAndAddCompanies(companiesBox.Items.Select(i => new Tuple<int?, string>(i.Id, i.Text)));


                movie.Update(name, thumb, image, year, runtime, descriptionBox.Text, tags, companies, people, movieFile);
                if (editMovie == null) Manager.AddMovie(movie);
                Close();
            }
            catch (Exception ex)
            {
                errorLabel.Content = ex.Message;
                errorLabel.ToolTip = ex.Message + " -- " + ex.StackTrace;
            }
        }

        private string GetRequiredText(string name, TextBox textBox, OneShotHandlerQueue<TextChangedEventArgs> oneShotHandler)
        {
            string text = textBox.Text.Trim();
            if (text == "")
            {
                oneShotHandler.Add((s, a) => errorLabel.Content = "");
                throw new Exception(name + " is required");
            }
            return text;
        }

        private int? GetTextBoxInteger(string name, TextBox textBox, OneShotHandlerQueue<TextChangedEventArgs> oneShotHandler)
        {
            string val = textBox.Text.Trim();
            if (val == "") return null;
            int ret;
            if (int.TryParse(val, out ret))
            {
                return ret;
            }
            oneShotHandler.Add((sender, args) => errorLabel.Content = "");
            throw new Exception(val + " is not a valid for " + name);
        }
    }
}
